#include "OpenGLWrapper.h"
#include <OpenGL/OpenGL.h>
#include <OpenGL/glu.h>
#include <GLUT/GLUT.h>
#include <math.h>
#include "Utils.h"

#include <iostream>
//#include "TransformController.h"

using namespace std;
using namespace gull::core;


unsigned short OpenGLWrapper::MAX_OPENGL_LIGHT = 8;

gullNotification
OpenGLWrapper::init3DContext()
{
	glClearColor(0.0f,0.0f,0.0f,0.0f);
	//glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
	int nbLight;
	glGetIntegerv(GL_MAX_LIGHTS, &nbLight);
	OpenGLWrapper::MAX_OPENGL_LIGHT = nbLight;
	for(int i = GL_LIGHT0; i < nbLight; i++)
	{
		m_lights.insert(lightPair(i, false));
	}
	return GULL_OK;
}

double*
convertMatrixToOpenGL(const Matrix4x3& m)
{
	double* mat = new double[16];
	
	mat[0] = m[0][0];
	mat[1] = m[0][1];
	mat[2] = m[0][2];
	mat[3] = 0.0;
	
	mat[4] = m[1][0];
	mat[5] = m[1][1];
	mat[6] = m[1][2];
	mat[7] = 0.0;
	
	mat[8] = m[2][0];
	mat[9] = m[2][1];
	mat[10] = m[2][2];
	mat[11] = 0.0;
	
	mat[12] = m[3][0];
	mat[13] = m[3][1];
	mat[14] = m[3][2];
	mat[15] = 1.0;
	return mat;
}

void
OpenGLWrapper::setMatrixWorld(const Matrix4x3& newMatrix) const
{
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	double* mat = convertMatrixToOpenGL(newMatrix);
	glMultMatrixd(mat);
	delete mat;
}


//
//	double* modelView = new double[16];
//		glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
//		for (int i = 0; i < 16; i++) {
//			cout << modelView[i] <<endl;
//		}


void
OpenGLWrapper::drawTriangle(const Vector3D& a, const Vector3D& b, const Vector3D& c) const
{
	
	glMatrixMode(GL_MODELVIEW);
	Vector3D ab = b - a;
	Vector3D cb = b - c;
	Vector3D n = (ab.cross(cb)).normalize();
	//glNormal3d(n[0], n[1], n[2]);

	
	glBegin(GL_TRIANGLES);
	glVertex3d(a.x(),a.y(),a.z());
	glVertex3d(b.x(),b.y(),b.z());
	glVertex3d(c.x(),c.y(),c.z());				
	glEnd();
}


void
OpenGLWrapper::drawTriangle(double edge) const
{
	glMatrixMode(GL_MODELVIEW);
	
	double z = 0.0;	
	glBegin(GL_TRIANGLES);
	//glNormal3d(0.0, 0.0, 1.0);
	glColor3d(0.05, 0.24, 0.42);
	glVertex4d(edge,-edge,z,1.0);
	glVertex4d(0.0f,edge,z,1.0);
	glVertex4d(-edge,-edge,z,1.0);				
	glEnd();
}

void
OpenGLWrapper::refreshFrame() const
{
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
}


void 
OpenGLWrapper::reshapeFrame(int w, int h) const
{
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	float fov = 60.0f;
	float near = 0.1f;
	float far = 100.0f;
	float topClipPlane = (float)tan(degToRad(fov*0.5)) * near;
	float bottomClipPlane = -topClipPlane;
	float leftClipPlane = (w/(float)h) *bottomClipPlane;
	float rightClipPlane = (w/(float)h) *topClipPlane;
	
	glFrustum(leftClipPlane, rightClipPlane, bottomClipPlane, topClipPlane , near, far);
	glMatrixMode(GL_MODELVIEW);
}

void
OpenGLWrapper::setLight(const LightNode& light) const
{
	const TransformController* tr = static_cast<const TransformController*>(light.getController(TRANSFORM));
	
	const Vector3D* v = tr->getPosition();
	const LightProperties* properties = light.getProperties();
	const Vector3D* diffusev = properties->getDiffuse();
	const Vector3D* specularv = properties->getSpecular();
	const Vector3D* ambientv = properties->getAmbient();
	
	GLfloat pos[] = {(GLfloat)(*v)[0],(GLfloat)(*v)[1],(GLfloat)(*v)[2]};
	GLfloat ambient[] = {(GLfloat)(*ambientv)[0],(GLfloat)(*ambientv)[1],(GLfloat)(*ambientv)[2]};
	GLfloat diffuse[] = {(GLfloat)(*diffusev)[0],(GLfloat)(*diffusev)[1],(GLfloat)(*diffusev)[2]};
	GLfloat specular[] = {(GLfloat)(*specularv)[0],(GLfloat)(*specularv)[1],(GLfloat)(*specularv)[2]};
	glLightfv(GL_LIGHT0, GL_POSITION, pos);
	
	glPushMatrix();
	glLoadIdentity();
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
	glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
	glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
	glPopMatrix();
	glEnable(GL_LIGHT0);
}

void 
OpenGLWrapper::setCamera(const Matrix4x3& cam) const
{
	
}
